package mint.modules.generator.expression;

import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

import org.antlr.runtime.tree.Tree;

import mint.MintLexer;
import mint.modules.generator.Scope;
import mint.modules.type.Type;

public class UnaryExprNode extends Expression {
	private Expression subExpr, auxExpr;
	private String operator;
	private List<String> errors;
	private int line;
	private Type type;

	public UnaryExprNode(Scope theParent, ExpressionType exprType, Tree unaryExprTree) {
		super(theParent, exprType);		
		operator = null;
		errors = new ArrayList<String>();
		type = null;
		line = unaryExprTree.getLine();
		auxExpr = null;
		
		if(unaryExprTree.getType() == MintLexer.POSITIVE)
		{
			operator = "+";
			subExpr = new UnaryExprNode(theParent, exprType, unaryExprTree.getChild(0));
		} else if(unaryExprTree.getType() == MintLexer.NEGATIVE)
		{
			operator = "-";
			subExpr = new UnaryExprNode(theParent, exprType, unaryExprTree.getChild(0));
		} else if(unaryExprTree.getType() == MintLexer.PREINCREMENT)
		{
			operator = "++";
			subExpr = new UnaryExprNode(theParent, ExpressionType.Left, unaryExprTree.getChild(0));
			auxExpr = new UnaryExprNode(theParent, ExpressionType.Right, unaryExprTree.getChild(0));
		} else if(unaryExprTree.getType() == MintLexer.PREDECREMENT)
		{
			operator = "--";
			subExpr = new UnaryExprNode(theParent, ExpressionType.Left, unaryExprTree.getChild(0));
			auxExpr = new UnaryExprNode(theParent, ExpressionType.Right, unaryExprTree.getChild(0));
		}
		else
		{
			subExpr = new UnaryExprNotPlusMinus(theParent, exprType, unaryExprTree);
		}
	}

	@Override
	public void testSemantic() {
		subExpr.testSemantic();
		type = subExpr.getType();
		
		if (operator != null)
		{
			if (getExpressionType() != ExpressionType.Right)
				errors.add(line + ": " + operator + " must be used on the right side of a expression");
			if (operator.equals("+") || operator.equals("-"))
			{
				if (subExpr.getType().equals(Type.floatType))
					type = Type.floatType;
				else if (subExpr.getType().equals(Type.intType))
					type = Type.intType;
				else
				{
					errors.add(line + ": " + operator + " expected int or float expression");
					type = Type.intType;
				}
			} else if (operator.equals("++") || operator.equals("--"))
			{
				if (!subExpr.getType().equals(Type.intType))
					errors.add(line + ": " + operator + " expected int expression");
				type = Type.intType;
				auxExpr.testSemantic();
			}
		}
	}

	@Override
	public List<String> getSemanticErrors() {
		errors.addAll(subExpr.getSemanticErrors());
		return errors;
	}

	@Override
	public void emit(Formatter output) {
		if (operator != null)
		{
			if (operator.equals("+"))
			{
				subExpr.emit(output);
			} else if (operator.equals("-"))
			{
				subExpr.emit(output);
				if (subExpr.getType().equals(Type.floatType))
					output.format("fneg\n");
				else
					output.format("ineg\n");
			} else if (operator.equals("++"))
			{
				subExpr.emit(output);
				auxExpr.emit(output);
				output.format("iconst_1\n");
				output.format("iadd\n");
				subExpr.leftEmit(output);
				auxExpr.emit(output);
			} else if (operator.equals("--"))
			{
				subExpr.emit(output);
				auxExpr.emit(output);
				output.format("iconst_1\n");
				output.format("isub\n");
				subExpr.leftEmit(output);
				auxExpr.emit(output);
			}
		} else
			subExpr.emit(output);
	}

	@Override
	public int getLine() {
		return line;
	}

	@Override
	public Type getType() {
		return type;
	}

	@Override
	public void leftEmit(Formatter output) {
		subExpr.leftEmit(output);
	}

}
